package xhhx.akka;

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.PoisonPill;
import akka.actor.Props;
import io.netty.channel.Channel;
import simpleProtobuf.SimpleProtobuf;
import xhhx.cache.PlayerCache;
import xhhx.manager.ActorManager;
import xhhx.manager.DataManager;
import xhhx.network.C2sMsg;
import xhhx.network.MsgType;
import xhhx.network.S2cMsg;
import xhhx.session.Player;

import java.util.HashMap;
import java.util.Map;

public class GateActor extends AbstractActor {
    private static Map<Integer, PlayerCache> map = new HashMap<>();
    private static Map<Channel, Link> linkMap = new HashMap<>();

    public static Props props() {
        return Props.create(GateActor.class);
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder()
                .match(Msg.class, msg -> {
                    dealwith(msg);
                })
                .match(RemoveMsg.class, removeMsg -> {
                    removeLink(removeMsg.ch);
                })
                .match(AddMsg.class, addMsg -> {
                    addLink(addMsg.ch);
                })
                .build();
    }

    //登陆验证
    private boolean verifyPlayer(Link link, C2sMsg msg) {
        if (link.playerCache != null) {
            // 已经登陆成功
            return true;
        }

        if (msg.msgId != MsgType.Login.msgId) {
            return false;
        }

        try {
            SimpleProtobuf.Login login = (SimpleProtobuf.Login) msg.receive;
            int loginId = login.getLoginId();
            int password = login.getPassWord();

            //返回信息
            SimpleProtobuf.LoginRt.Builder rt = SimpleProtobuf.LoginRt.newBuilder();

            PlayerCache p = getPlayerCacheByIdAndPwd(loginId, password);

            if (p == null) {
                //登陆失败
                S2cMsg s2c = new S2cMsg(msg.msgId, rt
                        .setRt(2)
                        .build());
                link.ch.writeAndFlush(s2c);
                return false;
            }

            link.playerCache = p;
            link.ref = ActorManager.GetSystem().actorOf(ConnectActor.props(link.ch));

            rt
                    .setRt(1)
                    .setPlayer(SimpleProtobuf.PlayerData.newBuilder()
                            .setName(p.player.getName())
                            .setLevel(p.player.getLevel()));
            S2cMsg s2c = new S2cMsg(msg.msgId, rt.build());
            link.ch.writeAndFlush(s2c);
        } catch (Exception e) {
            e.printStackTrace(System.err);
            return false;
        }

        return true;
    }

    private PlayerCache getPlayerCacheByIdAndPwd(int id, int password) {
        if (map.containsKey(id)) {
            //已经登陆
            return null;
        }

        Player p = DataManager.Get(id, Player.class);
        if (p != null && p.getPassword() != password) {
            //密码错误
            return null;
        }
        if (p == null) {
            //新玩家注册
            p = new Player();
            p.setId(id);
            p.setPassword(password);
            p.setName("Unknown");
            p.setLevel(1);
            DataManager.Insert(p);
        }
        PlayerCache playerCache = new PlayerCache();
        playerCache.player = p;

        map.put(id, playerCache);
        return playerCache;
    }

    private void dealwith(Msg msg) {
        Link link = getLink(msg.ch);
        try {
            if (!verifyPlayer(link, msg.msg)) {
                link.ch.close();
                return;
            }
            if (msg.msg.msgId == MsgType.Login.msgId) {
                return;
            }
            link.ref.tell(new ConnectActor.MsgResponder(msg.msg.msgId, msg.msg.receive, link.playerCache), ActorRef.noSender());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Link getLink(Channel ch) {
        Link link = linkMap.get(ch);
        return link;
    }

    public void removeLink(Channel ch) {
        Link link = linkMap.get(ch);
        try {
            if (link.ref != null && link.playerCache != null) {
                map.remove(link.playerCache.player.getId());
                link.ref.tell(PoisonPill.getInstance(), ActorRef.noSender());
            }
            linkMap.remove(ch);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Link addLink(Channel ch) {
        Link link = this.new Link(ch);
        linkMap.put(ch, link);
        return link;
    }


    public static class Msg {
        public final Channel ch;
        public final C2sMsg msg;

        public Msg(Channel ch, C2sMsg msg) {
            this.ch = ch;
            this.msg = msg;
        }
    }

    public static class RemoveMsg {
        public final Channel ch;

        public RemoveMsg(Channel ch) {
            this.ch = ch;
        }
    }

    public static class AddMsg {
        public final Channel ch;

        public AddMsg(Channel ch) {
            this.ch = ch;
        }
    }

    private class Link {
        private ActorRef ref;
        private PlayerCache playerCache;
        private Channel ch;

        public Link(Channel ch) {
            this.ch = ch;
        }
    }

}
